//package declarations
package pxgrid_utils;

//imports
import java.io.*;
import java.util.*;
import java.util.zip.*;
import org.apache.tools.tar.*;

/**
 * 
 * @author Steve Androulakis, Cyril Reboul & Mark Bate
 * 
 * A class to provide extraction methods for TAR and Zip archives.
 * 
 * Much of the code was lifted from tools contained within the TARDIS 
 * (The Australian Repositories for Diffraction Images) project 
 * (www.tardis.edu.au) written by Steve Androulakis, as well as from the 
 * Mr Sieve written by Cyril Reboul.
 */
public class PXArchiveUtils {
    //variables
    private static String archiveName;
    private static String destinationDir;

    /**
     * Extracts the archive archiveName to the directory destinationDir.
     * Essentially a wrapper for extractTarArchive() method.
     * 
     * @param archiveName String the name of the archive to be extracted
     * @param destinationDir String the directory to extract the archive to
     * @param deleteOriginalFile Boolean whether to delete original file or not
     * @return Boolean true if it extracted, else false
     * 
     */
    public static Boolean extractArchive(String archiveName, String archiveType, String destinationDir, Boolean deleteOriginalFile) {
        
        
        File destDirF = new File(destinationDir);
        PXArchiveUtils.destinationDir = destDirF.getAbsolutePath();
        PXArchiveUtils.archiveName = archiveName;

        
        if(archiveType.contains("zip")) {
            
            //if the archive didn't extract, chuck a hissyfit
            if(!extractZipArchive()) {
                return false;
            }
            
        } else {
        
            //if the archive didn't extract, chuck a hissyfit
            if(!extractTarArchive()) {
                return false;
            }
        }
        //delete the file if set
        if(deleteOriginalFile) {
            File fileToDelete = new File(PXArchiveUtils.destinationDir+"/"+PXArchiveUtils.archiveName);
            fileToDelete.delete();
        }
        
        // if we made it this far, return true
        return true;

    }

    
    /**
     * Extracts the archive PXArchiveUtils.archiveName to the directory 
     * PXArchiveUtils.destinationDir.
     * 
     * 
     * @return Boolean true if archive has been extracted, else false
     */
    private static Boolean extractTarArchive() {
        try {
            
            //get a FileInputStream
            FileInputStream in = new FileInputStream(new File(PXArchiveUtils.destinationDir+"/"+PXArchiveUtils.archiveName));
            System.out.println("Reading Archive File...");
            //get a TarInputStream from the FileInputStream
            TarInputStream ins = new TarInputStream(in);
            //get the next TarInputStream entry
            TarEntry archiveEntry = ins.getNextEntry();
         
            //check the directory exists
            if (new File(PXArchiveUtils.destinationDir).exists()) {

                //loop the TarInputStream entries
                while (archiveEntry != null) {

                    // checks that the archive entry isn't MAC OS X hidden file
                    // and that it's a PDB file
                    if(!archiveEntry.getName().startsWith(".")
                    && !archiveEntry.getName().startsWith("__")
                    && archiveEntry.getName().endsWith(".pdb")) {
                    
                        //set the destination path File
                        File destPath = new File(PXArchiveUtils.destinationDir
                                                + File.separatorChar
                                                + archiveEntry.getName());

                        System.out.println("Processing " + destPath.getAbsoluteFile());

                        //If the current tar entry is a regular file
                        if (!archiveEntry.isDirectory()) {

                            //do some crazy stuff to pull the file out
                            String pathStr = destPath.getPath();
                            int idx = pathStr.lastIndexOf(File.separatorChar);
                            if (idx > 0) {
                                File destDir = new File(pathStr.substring(0, idx));
                                destDir.mkdirs();
                            }

                            FileOutputStream fout = new FileOutputStream(destPath);
                            ins.copyEntryContents(fout);
                            fout.close();
                        }
                        //it's a directory, so make it
                        else {
                            destPath.mkdir();
                        }
                    }
                    //next!
                    archiveEntry = ins.getNextEntry();
                }
                //close the stream
                ins.close();
                in.close();
                System.out.println("Finished Extracting To " + PXArchiveUtils.destinationDir);
            }
            //the directory doesn't exist
            else {
                throw new Exception("That destination directory doesn't exist! " + PXArchiveUtils.destinationDir);
            }
        } catch (IOException e) {
            //if we didn't complete, return false
            System.out.println(PXArchiveUtils.archiveName + " not found for extraction. Exiting..."+e.getMessage());
            return false;
        } catch (Exception e) {
            //if we didn't complete, return false
            System.out.println(e.getMessage());
            return false;
        }

        //got this far, all done, return true!
        return true;
    }
    
    private static Boolean extractZipArchive () {
     try {
         
        List filelist = new ArrayList();
        BufferedOutputStream dest = null;
        FileInputStream fis = new FileInputStream(new File(PXArchiveUtils.destinationDir+"/"+PXArchiveUtils.archiveName));
        ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
        ZipEntry entry;
        int BUFFER = 10000000;
        
        
        //check the directory exists
        if (new File(PXArchiveUtils.destinationDir).exists()) {

            while((entry = zis.getNextEntry()) != null) {
                int count;
                byte data[] = new byte[BUFFER];

                // checks that the archive entry isn't MAC OS X hidden file
                // and that it's a PDB file
                if(!entry.getName().startsWith(".")
                    && !entry.getName().startsWith("__")
                    && entry.getName().endsWith(".pdb")) {

                    String entryname = PXArchiveUtils.destinationDir
                                        + File.separatorChar
                                        + entry.getName();

                    FileOutputStream fos = new FileOutputStream(entryname);
                    filelist.add(entryname);

                    dest = new BufferedOutputStream(fos, BUFFER);
                    while ((count = zis.read(data, 0, BUFFER)) != -1) {
                        dest.write(data, 0, count);
                    }
                    dest.flush();
                    dest.close();
                }
            }

            zis.close();
            return true;
        } else {
            throw new Exception("That destination directory doesn't exist! " + PXArchiveUtils.destinationDir);
        }
        
     } catch (IOException e) {
        //if we didn't complete, return false
        System.out.println(PXArchiveUtils.archiveName + " not found for extraction. Exiting..."+e.getMessage());
        return false;
     } catch (Exception e) {
        //if we didn't complete, return false
        System.out.println(e.getMessage());
        return false;
     }

  }

}
